home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / AppsToGo / DTS.Lib / CtlHandler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-24  |  37.2 KB  |  1,278 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        ctlhandler.c
  6. ** Written by:  Eric Soldan
  7. **
  8. ** Copyright © 1991-1993 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20. /* This code implements the new 7.0 human-interface standards for both
  21. ** TextEdit and List controls.  These standards include the following features:
  22. **
  23. ** 1) Tabbing between TextEdit and List controls within a window.
  24. ** 2) Displaying what item is active.  The active TextEdit item is indicated
  25. **    by either a blinking caret, or a selection range.
  26. ** 3) List positioning via the keyboard.  Entries on the keyboard automatically
  27. **    select and display the closest List item.  Also, the up and down arrows
  28. **    scroll through the list.
  29. ** 4) Window scrollbars are handled.
  30. */
  31.  
  32.  
  33.  
  34. /*****************************************************************************/
  35.  
  36.  
  37.  
  38. #include "DTS.Lib2.h"
  39. #include "DTS.Lib.protos.h"
  40.  
  41. #include "ListControlProcs.h"
  42. #include "TextEditControlProcs.h"
  43.  
  44. #ifndef __RESOURCES__
  45. #include <Resources.h>
  46. #endif
  47.  
  48. static void        OpenActionWindow(OSType sftype);
  49. static short    HandleScrollEvent(WindowPtr window, EventRecord *event);
  50.  
  51.  
  52.  
  53. /*****************************************************************************/
  54.  
  55.  
  56.  
  57. extern short        gBeginUpdateNested;
  58. extern Handle        gPopupProc;
  59. extern OSErr        gDialogErr;
  60.  
  61. short                gDataCtl = rDataCtl;
  62.  
  63. static FileRecHndl    gFrHndl;
  64. static Rect            gScrollRct;
  65. static Point        gKeepOrg;
  66. static Boolean        gVert;
  67.  
  68. static pascal void    ScrollActionProc(ControlHandle scrollCtl, short part);
  69. static void            ScrollTheContent(WindowPtr window, short h, short v);
  70. static short        GetCtlPosition(ControlHandle ctl);
  71.  
  72.  
  73.  
  74. /*****************************************************************************/
  75. /*****************************************************************************/
  76. /*****************************************************************************/
  77.  
  78.  
  79.  
  80. /* This function converts a control number to a control handle.  The function
  81. ** simply walks the window's control list counting down until it has reached
  82. ** the right control number.  It also returns the number of controls traversed.
  83. ** While often this will be the same as the control number passed in, if the
  84. ** number passed in is greater than the number of controls in the list, then
  85. ** the number returned is the number of controls in the list. */
  86.  
  87. /* NOTE: Additional support for control id's has been added.  To store the control id (cid),
  88. ** the control handle is grown, and the cid is stored after the control title.  This means
  89. ** that you can't directly call SetCTitle without losing the cid, as SetCTitle resizes the
  90. ** control handle.  You should instead call SetStyledCTitle, which preserves the cid.
  91. ** For backwards compatibility, CNum2Ctl and Ctl2CNum support both the old-style control
  92. ** numbers and the new-style control id's.  While backwards compatibility may be a good
  93. ** thing, what this means is that you have to assign your cid's so that the value is greater
  94. ** than the number of controls in the window. */
  95.  
  96. #pragma segment Controls
  97. short    CNum2Ctl(WindowPtr window, short ctlNum, ControlHandle *ctl)
  98. {
  99.     short    numCtls, cid;
  100.  
  101.     *ctl = nil;
  102.     if (!ctlNum) return(0);
  103.  
  104.     cid = ctlNum;    /* Caller may have actually passed us a cid. */
  105.  
  106.     *ctl = ((WindowPeek)window)->controlList;
  107.     for (numCtls = 1; --ctlNum;  ++numCtls) {
  108.         if (!*ctl) {
  109.             --numCtls;
  110.             break;
  111.         }
  112.         if (GetControlID(*ctl) == cid) break;
  113.         *ctl = (**ctl)->nextControl;
  114.     }
  115.  
  116.     return(numCtls);
  117. }
  118.  
  119.  
  120.  
  121. /*****************************************************************************/
  122.  
  123.  
  124.  
  125. /* This function converts a control handle to a control number.  The function
  126. ** simply walks the window's control list and counts how many controls it
  127. ** has to traverse before finding the target control.  The smallest control
  128. ** number that can be returned is 1.  This makes control numbers similar to
  129. ** dialog item numbers. */
  130.  
  131. /* NOTE: Additional support for control id's has been added.  To store the control id (cid),
  132. ** the control handle is grown, and the cid is stored after the control title.  This means
  133. ** that you can't directly call SetCTitle without losing the cid, as SetCTitle resizes the
  134. ** control handle.  You should instead call SetStyledCTitle, which preserves the cid.
  135. ** For backwards compatibility, CNum2Ctl and Ctl2CNum support both the old-style control
  136. ** numbers and the new-style control id's.  While backwards compatibility may be a good
  137. ** thing, what this means is that you have to assign your cid's so that the value is greater
  138. ** than the number of controls in the window. */
  139.  
  140. #pragma segment Controls
  141. short    Ctl2CNum(ControlHandle ctl)
  142. {
  143.     ControlHandle    nextCtl;
  144.     short            ctlNum;
  145.  
  146.     if (!ctl)   return(0);
  147.     ctlNum = GetControlID(ctl);
  148.     if (ctlNum) return(ctlNum);
  149.  
  150.     nextCtl = ((WindowPeek)(*ctl)->contrlOwner)->controlList;
  151.     for (ctlNum = 0;;) {
  152.         if (!nextCtl) break;
  153.         ++ctlNum;
  154.         if (ctl == nextCtl) break;
  155.         nextCtl = (*nextCtl)->nextControl;
  156.     }
  157.     return(ctlNum);
  158. }
  159.  
  160.  
  161.  
  162. /*****************************************************************************/
  163.  
  164.  
  165.  
  166. /* This function reactivates the last active TextEdit or List control for
  167. ** the indicated window. */
  168.  
  169. #pragma segment Controls
  170. void    DoCtlActivate(WindowPtr window)
  171. {
  172.     ListHandle    list;
  173.     TEHandle    te, oldte;
  174.     WindowPtr    oldww;
  175.  
  176.     list = (*gclWindActivate)(window, false);
  177.     if (list) {
  178.         if ((*list)->rView.left < -8192)
  179.             BeginFrame(window);
  180.         else
  181.             BeginContent(window);
  182.         (*gclWindActivate)(window, true);        /* Reactivate the list. */
  183.         EndContent(window);                        /* Same as EndFrame().  */
  184.         return;
  185.     }
  186.  
  187.     oldte = (*gcteFindActive)(nil);
  188.     te    = (*gcteWindActivate)(window, false);
  189.     if (te != oldte) {
  190.         if (oldte) {
  191.             oldww = (*oldte)->inPort;
  192.             if ((*oldte)->viewRect.left < -8192)
  193.                 BeginFrame(oldww);
  194.             else
  195.                 BeginContent(oldww);
  196.             (*gcteWindActivate)(oldww, true);
  197.             EndContent(oldww);
  198.         }
  199.         if (te) {
  200.             if ((*te)->viewRect.left < -8192)
  201.                 BeginFrame(window);
  202.             else
  203.                 BeginContent(window);
  204.             (*gcteWindActivate)(window, true);
  205.             EndContent(window);
  206.         }
  207.     }
  208. }
  209.  
  210.  
  211.  
  212. /*****************************************************************************/
  213.  
  214.  
  215.  
  216. /* This function returns all the checkBox values into the dsignated array.
  217. ** The function walks the control list, and when it finds a checkBox control,
  218. ** it gets the control value and places it in the next position in the array.
  219. ** This allows a single call to retrieve all the checkBox values at once. */
  220.  
  221. #pragma segment Controls
  222. void    GetCheckBoxValues(WindowPtr window, Boolean checkBoxVal[])
  223. {
  224.     ControlHandle    nextCtl;
  225.     short            checkBoxIndx;
  226.  
  227.     nextCtl = ((WindowPeek)window)->controlList;
  228.     for (checkBoxIndx = 0;;) {
  229.         if (!nextCtl) return;
  230.         if (GetButtonVariant(nextCtl) == checkBoxProc)
  231.             checkBoxVal[checkBoxIndx++] = GetControlValue(nextCtl);
  232.         nextCtl = (*nextCtl)->nextControl;
  233.     }
  234. }
  235.  
  236.  
  237.  
  238. /*****************************************************************************/
  239.  
  240.  
  241.  
  242. /* This function returns which radio button is selected for a particular
  243. ** family of radio buttons.  It finds the radio button of the target family
  244. ** with the lowest control number and it subtracts this number from the
  245. ** selected radio button of the same family.  This gives a relative radio
  246. ** button number as a return result.  This way the position of the family
  247. ** of radio buttons can change in the window and the return result is the
  248. ** same.  The family number is stored in the control's refCon field. */
  249.  
  250. #pragma segment Controls
  251. short    GetRadioButtonChoice(WindowPtr window, short famNum)
  252. {
  253.     ControlHandle    nextCtl;
  254.     short            firstInFam, cnum, chosen;
  255.  
  256.     nextCtl = ((WindowPeek)window)->controlList;
  257.     for (firstInFam = chosen = 0;;) {
  258.         if (!nextCtl) {
  259.             if (!chosen) return(-1);
  260.                 /* If a proper radio button family was passed in, this can't
  261.                 ** happen.  The -1 is an error that indicates that the
  262.                 ** requested family didn't exist, or that there was no selected
  263.                 ** radio of the requested family. */
  264.             return(chosen - firstInFam);
  265.         }
  266.         if (GetButtonVariant(nextCtl) == radioButProc) {
  267.             if (GetControlReference(nextCtl) == famNum) {
  268.                 cnum = Ctl2CNum(nextCtl);
  269.                 if (!firstInFam)
  270.                     firstInFam = cnum;
  271.                 else {
  272.                     if (firstInFam > cnum)
  273.                         firstInFam = cnum;
  274.                 }
  275.                 if (GetControlValue(nextCtl)) chosen = cnum;
  276.             }
  277.         }
  278.         nextCtl = (*nextCtl)->nextControl;
  279.     }
  280. }
  281.  
  282.  
  283.  
  284. /*****************************************************************************/
  285.  
  286.  
  287.  
  288. /* This function currently handles events for TextEdit, List, and button
  289. ** controls in a window.  It also handles the window scrollbars and
  290. ** scrolling of the window. */
  291.  
  292. #pragma segment Controls
  293. short    IsCtlEvent(WindowPtr window, EventRecord *event, ControlHandle *retCtl, short *retAction)
  294. {
  295.     RgnHandle            docScroller, docFrame, oldClip, newClip;
  296.     TEHandle            te, oldte, teNext;
  297.     ListHandle            list, oldlist, listNext;
  298.     ControlHandle        xxx, activeCtl, teCtl, listCtl, nextCtl, newCtl, dataCtl, cc;
  299.     short                ctlNum, key, modifiers, mode, action, dir, pass, visMode;
  300.     short                thisNum, teNum, listNum, i, oldVal, newVal, dpass, part;
  301.     Boolean                hitFrame, hitScrollBar, tracked, hasBalloon, didPopup, didKey;
  302.     CTEDataHndl            teData;
  303.     CLDataHndl            listData;
  304.     EventRecord            evt;
  305.     WindowPtr            ww;
  306.     ControlStyleInfo    cinfo;
  307.     short                targetChr, targetMod;
  308.     Str255                dataCtlTitle;
  309.     OSType                sftype, sftypeNW;
  310.     Rect                org;
  311.     Point                org2;
  312.     Point                mouseLoc;
  313. #ifndef powerc
  314.     FileRecHndl            ff;
  315.     RgnHandle            rgn;
  316. #endif
  317.  
  318.     static ControlActionUPP    cupp;
  319.  
  320.     pass = 0;
  321.     sftypeNW = 0;
  322.  
  323.     if (!retCtl)    retCtl    = &xxx;
  324.     if (!retAction) retAction = &action;
  325.  
  326.     *retCtl    = nil;
  327.     *retAction = 0;
  328.  
  329.     evt = *event;
  330.  
  331.     if (evt.what == nullEvent) {
  332.         mouseLoc = GetGlobalMouse();
  333.         window   = FrontWindowOfType(kwIsModalDialog, true);
  334.  
  335. #ifndef powerc
  336.         if (window) {
  337.             ff = (FileRecHndl)GetWRefCon(window);
  338.             if (ff) {
  339.                 if ((*ff)->fileState.sfType == '6hlp') {
  340.                     for (; (window = GetNextWindow(window, 0)) != nil;) {
  341.                         if (((WindowPeek)window)->visible) break;
  342.                     }
  343.                 }
  344.             }
  345.         }
  346. #endif
  347.  
  348.         if (!window) {
  349.             part = FindWindow(mouseLoc, &window);
  350. #ifndef powerc
  351.             if (ww = GetNextWindow(nil, '6hlp')) {
  352.                 if (ww == window) {        /* We found the help window -- that's bad. */
  353.                     CopyRgn(((WindowPeek)ww)->strucRgn, rgn = NewRgn());
  354.                     OffsetRgn(((WindowPeek)ww)->strucRgn, 16384, 0);
  355.                     OffsetRgn(((WindowPeek)ww)->contRgn,  16384, 0);
  356.                     CalcVisBehind((WindowPeek)ww, rgn);
  357.                     DisposeRgn(rgn);
  358.                     part = FindWindow(mouseLoc, &window);
  359.                     OffsetRgn(((WindowPeek)ww)->strucRgn, -16384, 0);
  360.                     OffsetRgn(((WindowPeek)ww)->contRgn,  -16384, 0);
  361.                     CalcVisBehind((WindowPeek)ww, ((WindowPeek)ww)->strucRgn);
  362.                 }
  363.             }
  364. #endif
  365.             if (part == inContent)
  366.                 if (!(((WindowPeek)window)->hilited))
  367.                     window = nil;
  368.         }
  369.         hasBalloon = false;
  370.         if (IsDAWindow(window)) window = nil;
  371.         if (window) {
  372.             if (PtInRgn(mouseLoc, ((WindowPeek)window)->contRgn)) {
  373.                 SetPort(window);
  374.                 org = window->portRect;
  375.  
  376.                 docFrame = DoCalcFrameRgn(window);
  377.                 hitFrame = PtInRgn(mouseLoc, docFrame);
  378.                 DisposeRgn(docFrame);
  379.  
  380.                 if (hitFrame) {
  381.                     BeginFrame(window);        /* This sets the origin for the frame. */
  382.                     EndFrame(window);        /* This DOESN'T reset the origin for the frame, so the origin is now set correctly. */
  383.                     hasBalloon = ControlBalloonHelp(window, event->modifiers, mouseLoc);
  384.                 }
  385.                 else {
  386.                     BeginContent(window);    /* This sets the origin for the content. */
  387.                     EndContent(window);        /* This DOESN'T reset the origin for the content, so the origin is now set correctly. */
  388.                     hasBalloon = ControlBalloonHelp(window, event->modifiers, mouseLoc);
  389.                 }
  390.                 SetOrigin(org.left, org.top);
  391.             }
  392.         }
  393.         if (!hasBalloon) {
  394. #ifndef powerc
  395.             if (ww = GetNextWindow(nil, '6hlp')) DisposeOneWindow(ww, kClose);
  396. #endif
  397.             ControlBalloonHelp(nil, event->modifiers, mouseLoc);
  398.         }
  399.         return(0);
  400.     }
  401.  
  402.     if (!window) return(0);
  403.  
  404.     org = window->portRect;
  405.  
  406.     if (evt.what == mouseDown) {
  407.  
  408.         docScroller = DoCalcScrollRgn(window);
  409.         hitFrame    = PtInRgn(evt.where, docScroller);
  410.         DisposeRgn(docScroller);
  411.         if (hitFrame) return(HandleScrollEvent(window, &evt));
  412.             /* If window scrollbar is clicked on, handle the window scroll event. */
  413.  
  414.         docFrame = DoCalcFrameRgn(window);
  415.         hitFrame = PtInRgn(evt.where, docFrame);
  416.         DisposeRgn(docFrame);
  417.  
  418.         evt.where = event->where;
  419.         if (hitFrame)
  420.             BeginFrame(window);
  421.         else
  422.             BeginContent(window);
  423.         GlobalToLocal(&evt.where);
  424.  
  425.         (*gcteCtlHit)();    /* Clear CTECtl defProc's last hit CTECtl. */
  426.         (*gclCtlHit)();        /* Clear CLCtl defProc's last hit CLCtl. */
  427.  
  428.         if (WhichControl(evt.where, 0, window, retCtl)) {
  429.                 /* WhichControl also finds inactive controls.  We need this for scrollbars.
  430.                 ** If an inactive scrollbar is hit, we should activate the related
  431.                 ** TextEdit or List control. */
  432.  
  433.             hitScrollBar = IsScrollBar(*retCtl);
  434.                 /* The List controls and TextEdit controls may have scrollbars.
  435.                 ** Find out if a scrollbar was pressed, because it may belong
  436.                 ** to a TextEdit or List control. */
  437.  
  438.             part = FindControl(evt.where, window, retCtl);
  439.                 /* WhichControl doesn't call the scrollProc.  FindControl does.
  440.                 ** We need it called so we can determine below if a TextEdit or
  441.                 ** List control was hit.  CTECtlHit() and CLCtlHit() return
  442.                 ** the last hit respective control. */
  443.  
  444.             ctlNum = Ctl2CNum(*retCtl);
  445.  
  446.             if ((hitScrollBar) || ((*gcteCtlHit)())) {
  447.                     /* This test is for speed.  CTEClick would find out if a TextEdit
  448.                     ** control handled the mouse click, but not as fast as we would
  449.                     ** like.  The above test determines if it is worth investigating. */
  450.  
  451.                 cc = CTEFindCtl(window, event, &te, nil);
  452.                 if (cc) {
  453.  
  454.                     if ((*cc)->contrlHilite != 255) {
  455.                         ww = CTETargetInfo(&oldte, nil);
  456.                         SetOrigin(org.left, org.top);
  457.                         EndContent(window);
  458.  
  459.                         if ((oldte) && (te != oldte)) {
  460.                             if ((*oldte)->viewRect.left < -8192)
  461.                                 BeginFrame(ww);
  462.                             else
  463.                                 BeginContent(ww);
  464.                             (*gcteActivate)(false, oldte);
  465.                             SetOrigin(org.left, org.top);
  466.                             EndContent(ww);
  467.                         }
  468.                         list = (*gclFindActive)(window);
  469.                         if (list) {
  470.                             cc = CLViewFromList(list);
  471.                             listData = (CLDataHndl)(*cc)->contrlData;
  472.                             mode     = (*listData)->mode;
  473.                             if (mode & (clShowActive | clKeyPos)) {
  474.                                 if ((*list)->rView.left < -8192)
  475.                                     BeginFrame(window);
  476.                                 else
  477.                                     BeginContent(window);
  478.                                 (*gclActivate)(false, list);
  479.                                 SetOrigin(org.left, org.top);
  480.                                 EndContent(window);
  481.                             }
  482.                         }
  483.                         if (evt.where.h < -8192)
  484.                             BeginFrame(window);
  485.                         else
  486.                             BeginContent(window);
  487.                     }
  488.  
  489.                     if ((*gcteClick)(window, event, retAction)) {    /* If click for TE control... */
  490.                         if (*retAction == -1) {
  491.                             *retCtl = (*gcteViewFromTE)(CTEFindActive(window));
  492.                             teData  = (CTEDataHndl)(**retCtl)->contrlData;
  493.                             mode    = (*teData)->mode;
  494.                             if (!(mode & cteTwoStep))
  495.                                 (*gcteClick)(window, event, retAction);
  496.                         }
  497.                         SetOrigin(org.left, org.top);
  498.                         EndContent(window);
  499.                         return(ctlNum);
  500.                     }
  501.                 }
  502.             }
  503.  
  504.             if ((hitScrollBar) || ((*gclCtlHit)())) {
  505.                     /* This test is for speed.  CLClick would find out if a List
  506.                     ** control handled the mouse click, but not as fast as we would
  507.                     ** like.  The above test determines if it is worth investigating. */
  508.  
  509.                 cc = CLFindCtl(window, event, &list, nil);
  510.                 if (cc) {
  511.                     if ((*cc)->contrlHilite != 255) {
  512.                         oldlist = CLFindActive(window);
  513.                         SetOrigin(org.left, org.top);
  514.                         EndContent(window);
  515.                         if ((oldlist) && (list != oldlist)) {
  516.                             if ((*oldlist)->rView.left < -8192)
  517.                                 BeginFrame(window);
  518.                             else
  519.                                 BeginContent(window);
  520.                             (*gclActivate)(false, oldlist);
  521.                             SetOrigin(org.left, org.top);
  522.                             EndContent(window);
  523.                         }
  524.                         if (list) {
  525.                             cc = CLViewFromList(list);
  526.                             listData = (CLDataHndl)(*cc)->contrlData;
  527.                             mode     = (*listData)->mode;
  528.                             if (mode & (clShowActive | clKeyPos)) {
  529.                                 te = (*gcteFindActive)(window);
  530.                                 if (te) {
  531.                                     if ((*te)->viewRect.left < -8192)
  532.                                         BeginFrame(window);
  533.                                     else
  534.                                         BeginContent(window);
  535.                                     (*gcteActivate)(false, te);
  536.                                     SetOrigin(org.left, org.top);
  537.                                     EndContent(window);
  538.                                 }
  539.                             }
  540.                         }
  541.                         if (evt.where.h < -8192)
  542.                             BeginFrame(window);
  543.                         else
  544.                             BeginContent(window);
  545.                     }
  546.  
  547.                     if ((*gclClick)(window, event, retAction)) {    /* If click for List control... */
  548.                         if (*retAction == -1) {        /* Just activated a List control... */
  549.                             *retCtl  = (*gclViewFromList)((*gclFindActive)(window));
  550.                             listData = (CLDataHndl)(**retCtl)->contrlData;
  551.                             mode     = (*listData)->mode;
  552.                             if (!(mode & clTwoStep))
  553.                                 (*gclClick)(window, event, retAction);
  554.                         }
  555.                         SetOrigin(org.left, org.top);
  556.                         EndContent(window);
  557.                         return(ctlNum);
  558.                     }
  559.                 }
  560.             }
  561.  
  562.             didPopup = tracked = false;
  563.             WhichControl(evt.where, 0, window, retCtl);
  564.             if (gPopupProc) {        /* The popup control does not handle negative coords. */
  565.                 LoadResource(gPopupProc);
  566.                 if ((*(**retCtl)->contrlDefProc) == (*gPopupProc)) {
  567.                     didPopup = true;
  568.                     org2.h = window->portRect.left;
  569.                     org2.v = window->portRect.top;
  570.                     GetClip(oldClip = NewRgn());
  571.                     RectRgn(newClip = NewRgn(), &(window->portRect));
  572.                     SectRgn(newClip, oldClip, newClip);
  573.                     SetOrigin(0, 0);
  574.                     OffsetRgn(newClip, -org2.h, -org2.v);
  575.                     SetClip(newClip);
  576.                     OffsetRect(&((**retCtl)->contrlRect), -org2.h, -org2.v);
  577.                     oldVal  = (**retCtl)->contrlValue;
  578.                     UseControlStyle(*retCtl);
  579.                     cinfo.trackProc = nil;
  580.                     GetControlStyle(*retCtl, &cinfo);
  581.                     if (cinfo.trackProc)
  582.                         tracked = (*cinfo.trackProc)(*retCtl, part, &evt);
  583.                     else {
  584.                         if (!cupp) cupp = (ControlActionUPP)(-1);
  585.                         tracked = TrackControl(*retCtl, evt.where, cupp);
  586.                     }
  587.                     newVal = (**retCtl)->contrlValue;
  588.                     UseControlStyle(nil);
  589.                     ctlNum = 0;
  590.                     if (oldVal != newVal) {
  591.                         tracked = true;
  592.                         ctlNum  = Ctl2CNum(*retCtl);
  593.                     }
  594.                     OffsetRect(&((**retCtl)->contrlRect), org2.h, org2.v);
  595.                     SetOrigin(org2.h, org2.v);
  596.                     SetClip(oldClip);
  597.                     DisposeRgn(oldClip);
  598.                     DisposeRgn(newClip);
  599.                     DoDraw1Control(*retCtl, false);
  600.                 }
  601.             }
  602.  
  603.             *retAction = 0;
  604.  
  605.             if (!didPopup) {
  606.                 FindControl(evt.where, window, retCtl);
  607.                 if (!*retCtl) {
  608.                     SetOrigin(org.left, org.top);
  609.                     EndContent(window);
  610.                     return(ctlNum);
  611.                 }
  612.  
  613.                 WhichControl(evt.where, evt.when, window, nil);
  614.                     /* WhichControl places the hit control in the global gWhichCtl.
  615.                     ** This global is used by CCIconCtl to determine double-clicks.
  616.                     ** Double-clicking is also calculated by WhichControl.  The global
  617.                     ** gWhichCtlDbl is set true if the control was double-clicked on.
  618.                     ** We call WhichControl with the click time just prior to tracking
  619.                     ** the control.  When a non-0 tick is passed in, it compares the found
  620.                     ** control against the last found control, and the tick against the last
  621.                     ** tick.  The globals are set accordingly. */
  622.  
  623.                 oldVal = (**retCtl)->contrlValue;
  624.                 UseControlStyle(*retCtl);
  625.                 cinfo.trackProc = nil;
  626.                 GetControlStyle(*retCtl, &cinfo);
  627.                 if (cinfo.trackProc)
  628.                     tracked = (*cinfo.trackProc)(*retCtl, part, &evt);
  629.                 else {
  630.                     if (!cupp) cupp = (ControlActionUPP)(-1);
  631.                     tracked = TrackControl(*retCtl, evt.where, cupp);
  632.                 }
  633.                 UseControlStyle(nil);
  634.             }
  635.     
  636.             if (tracked) {                    /* Handle other controls. */
  637.  
  638.                 switch(GetButtonVariant(*retCtl)) {
  639.                     case pushButProc:
  640.                         break;
  641.                     case checkBoxProc:
  642.                         SetStyledCtlValue(*retCtl, GetControlValue(*retCtl) ^ 1);
  643.                                 /* Toggle checkBox value. */
  644.                         break;
  645.                     case radioButProc:
  646.                         nextCtl = ((WindowPeek)window)->controlList;
  647.                             /* The below loop walks the control list for the window and
  648.                             ** finds radio buttons of the correct family number.  If
  649.                             ** the found radio button is the one that was clicked on,
  650.                             ** the value is set true, otherwise it is set false. */
  651.                         for (; nextCtl; nextCtl = (*nextCtl)->nextControl) {
  652.                             if (GetButtonVariant(nextCtl) == radioButProc)
  653.                                 if (GetControlReference(nextCtl) == GetControlReference(*retCtl))
  654.                                     SetStyledCtlValue(nextCtl, (nextCtl == *retCtl));
  655.                         }
  656.                         break;
  657.                 }
  658.  
  659.                 newVal = (**retCtl)->contrlValue;
  660.  
  661.                 if (GetControlStyle(*retCtl, &cinfo)) {
  662.                     for (i = 1;; i += 6) {
  663.                         if (i >= cinfo.keyEquivs[0]) break;
  664.                         if (cinfo.keyEquivs[i] == (unsigned char)',') ++i;
  665.                         if (cinfo.keyEquivs[i] == (unsigned char)'\'')
  666.                             BlockMove(cinfo.keyEquivs + i + 1, (Ptr)&sftypeNW, sizeof(OSType));
  667.                         if (cinfo.keyEquivs[i] == (unsigned char)':') {
  668.                             targetChr = GetHexByte((char *)(cinfo.keyEquivs + i + 1));
  669.                             targetMod = GetHexByte((char *)(cinfo.keyEquivs + i + 2 + 1)) << 8;
  670.                             evt.what       = keyDown;
  671.                             evt.message    = targetChr;
  672.                             evt.modifiers &= 0x00FF;
  673.                             evt.modifiers |= (targetMod << 8);
  674.                             pass = 1;
  675.                             if (cinfo.keyEquivs[0] > i + 4)
  676.                                 if (cinfo.keyEquivs[i + 5] == '<')
  677.                                     pass = 0;
  678.                                         /* If delimiter is a <, then reprocess with
  679.                                         ** pass #0.  This could cause an infinite loop
  680.                                         ** if the targetEquiv is the same as what was
  681.                                         ** pressed.  The reason that this is done is if
  682.                                         ** the targetEquiv is different than the original
  683.                                         ** event, and we want to give non-te, non-list controls
  684.                                         ** a chance to process the equiv.  Normally the whole
  685.                                         ** purpose for this feature is to first notice that a
  686.                                         ** pass-0 control has an equiv, and then we want to pass
  687.                                         ** this key onto a te control. */
  688.                         }
  689.                     }
  690.                 }
  691.  
  692.                 if (oldVal != newVal) {
  693.                     *retAction = 3;
  694.                     oldVal -= (**retCtl)->contrlMin;
  695.                     newVal -= (**retCtl)->contrlMin;
  696.                     CNum2Ctl(window, -ctlNum, &dataCtl);
  697.                     if (dataCtl) {
  698.                         GetControlTitle(dataCtl, dataCtlTitle);
  699.                         switch (GetControlVariant(dataCtl)) {
  700.                             case 0:
  701.                                 for (dpass = 0; dpass < 2; ++dpass) {
  702.                                     i  = (dpass) ? newVal : oldVal;
  703.                                     i *= 7;
  704.                                     i += 2;
  705.                                     if (i <= dataCtlTitle[0] - 3) {
  706.                                         BlockMove(dataCtlTitle + i, &sftype, sizeof(OSType));
  707.                                         visMode = (dpass) ? kwStandardVis : kwHideAll;
  708.                                         DisplayControlSet(window, sftype, visMode);
  709.                                     }
  710.                                 }
  711.                                 break;
  712.                         }
  713.                     }
  714.                 }
  715.             }
  716.             else {
  717.                 *retCtl = nil;
  718.                 ctlNum = 0;
  719.             }
  720.  
  721.             SetOrigin(org.left, org.top);
  722.             EndContent(window);
  723.  
  724.             if (evt.what != keyDown) {
  725.                 if (sftypeNW) OpenActionWindow(sftypeNW);
  726.                 return(ctlNum);
  727.             }
  728.         }
  729.  
  730.         if (evt.what != keyDown) {
  731.             SetOrigin(org.left, org.top);
  732.             EndContent(window);
  733.             if (sftypeNW) OpenActionWindow(sftypeNW);
  734.             return(0);
  735.         }
  736.     }
  737.  
  738.     if ((evt.what == keyDown) || (evt.what == autoKey)) {        /* If event was keypress... */
  739.  
  740.         modifiers = evt.modifiers;
  741.         key       = evt.message & charCodeMask;
  742.         dir       = (modifiers & shiftKey) ? -1 : 1;
  743.  
  744.         if (key == chTab) {        /* If tab... */
  745.  
  746.             teNext    = nil;
  747.             listNext  = nil;
  748.             activeCtl = nil;
  749.  
  750.             list = (*gclFindActive)(window);
  751.             if (list) {
  752.                 activeCtl = (*gclViewFromList)(list);    /* Find what the active control is. */
  753.                 listData = (CLDataHndl)(*activeCtl)->contrlData;
  754.                 mode     = (*listData)->mode;
  755.                 if (!(mode & (clShowActive | clKeyPos)))
  756.                     activeCtl = nil;
  757.                         /* Find out if active List control supports key
  758.                         ** positioning and/or show active. */
  759.             }
  760.  
  761.             te = (*gcteFindActive)(window);
  762.             if (te)
  763.                 activeCtl = (*gcteViewFromTE)(te);
  764.  
  765.             if (!(teCtl = (*gcteNext)(window, &teNext, activeCtl, dir, true)))
  766.                 teCtl = (*gcteNext)(window, &teNext, nil, dir, true);
  767.                     /* Find the next TextEdit control from the active control. */
  768.  
  769.             listCtl = activeCtl;
  770.             for (; (listCtl = (*gclNext)(window, &listNext, listCtl, dir, true)) != nil;) {
  771.                 listData = (CLDataHndl)(*listCtl)->contrlData;
  772.                 mode     = (*listData)->mode;
  773.                 if (mode & (clShowActive | clKeyPos)) break;
  774.             }
  775.             if (!listCtl) {
  776.                 for (; (listCtl = (*gclNext)(window, &listNext, listCtl, dir, true)) != nil;) {
  777.                     listData = (CLDataHndl)(*listCtl)->contrlData;
  778.                     mode     = (*listData)->mode;
  779.                     if (mode & (clShowActive | clKeyPos)) break;
  780.                 }
  781.             }
  782.  
  783.             if ((!teNext) && (!listNext)) return(0);
  784.                 /* No TextEdit or List controls in window, so we are done. */
  785.  
  786.             thisNum = GetCtlPosition(activeCtl);
  787.             teNum   = GetCtlPosition(teCtl);
  788.             listNum = GetCtlPosition(listCtl);
  789.  
  790.             newCtl = activeCtl;
  791.             if (dir == 1) {
  792.                 if (!teNum)   teNum   = 32767;
  793.                 if (!listNum) listNum = 32767;
  794.                 if (teNum   <= thisNum) teNum   += 16384;
  795.                 if (listNum <= thisNum) listNum += 16384;
  796.                 if (teNum < listNum) newCtl = teCtl;
  797.                 if (listNum < teNum) newCtl = listCtl;
  798.             }
  799.             else {
  800.                 if (!teNum)   teNum   = -32767;
  801.                 if (!listNum) listNum = -32767;
  802.                 if (teNum   >= thisNum) teNum   -= 16384;
  803.                 if (listNum >= thisNum) listNum -= 16384;
  804.                 if (teNum > listNum) newCtl = teCtl;
  805.                 if (listNum > teNum) newCtl = listCtl;
  806.             }
  807.  
  808.             if (activeCtl == newCtl) {
  809.                 if (newCtl == teCtl) {
  810.                     if ((*teNext)->viewRect.left < -8192)
  811.                         BeginFrame(window);
  812.                     else
  813.                         BeginContent(window);
  814.                     (*gcteActivate)(true, teNext);
  815.                     teData = (CTEDataHndl)(*teCtl)->contrlData;
  816.                     if ((*teData)->mode & cteTabSelectAll)
  817.                         (*gcteSetSelect)(0, (*teNext)->teLength, teNext);
  818.                             /* If the "select all TextEdit text when tabbed into" bit is
  819.                             ** set, then do that very thing. */
  820.                     SetOrigin(org.left, org.top);
  821.                     EndContent(window);
  822.                 }
  823.                 return(0);
  824.             }
  825.  
  826.             if (te) {            /* If old ctl is te, deactivate it. */
  827.                 if ((*te)->viewRect.left < -8192)
  828.                     BeginFrame(window);
  829.                 else
  830.                     BeginContent(window);
  831.                 (*gcteActivate)(false, te);
  832.                 SetOrigin(org.left, org.top);
  833.                 EndContent(window);
  834.             }
  835.  
  836.             if (list) {            /* If old ctl is list, deactivate it. */
  837.                 if ((*list)->rView.left < -8192)
  838.                     BeginFrame(window);
  839.                 else
  840.                     BeginContent(window);
  841.                 (*gclActivate)(false, list);
  842.                 SetOrigin(org.left, org.top);
  843.                 EndContent(window);
  844.             }
  845.  
  846.             if (newCtl == teCtl) {
  847.                 if ((*teNext)->viewRect.left < -8192)
  848.                     BeginFrame(window);
  849.                 else
  850.                     BeginContent(window);
  851.                 (*gcteActivate)(true, teNext);
  852.                 teData = (CTEDataHndl)(*teCtl)->contrlData;
  853.                 if ((*teData)->mode & cteTabSelectAll)
  854.                     (*gcteSetSelect)(0, (*teNext)->teLength, teNext);
  855.                         /* If the "select all TextEdit text when tabbed into" bit is
  856.                         ** set, then do that very thing. */
  857.                 SetOrigin(org.left, org.top);
  858.                 EndContent(window);
  859.                 return(Ctl2CNum(*retCtl = teCtl));
  860.             }
  861.  
  862.             if (newCtl == listCtl) {
  863.                 if ((*listNext)->rView.left < -8192)
  864.                     BeginFrame(window);
  865.                 else
  866.                     BeginContent(window);
  867.                 (*gclActivate)(true, listNext);
  868.                 SetOrigin(org.left, org.top);
  869.                 EndContent(window);        /* Remove the clipping. */
  870.                 return(Ctl2CNum(*retCtl = listCtl));
  871.             }
  872.         }
  873.  
  874.         for (; pass < 3; ++pass) {
  875.             switch (pass) {
  876.                 case 0:
  877.                 case 2:
  878.                     if (ControlKeyEquiv(window, &evt, retCtl, ((pass) ? "\p031900,0D1900" :
  879.                                                                         "\p031900"))) {
  880.                         if ((**retCtl)->contrlRect.left < -8192)
  881.                             BeginFrame(window);
  882.                         else
  883.                             BeginContent(window);
  884.                         SelectButton(*retCtl);
  885.                         oldVal = GetControlValue(*retCtl);
  886.                         switch(GetButtonVariant(*retCtl)) {
  887.                             case pushButProc:
  888.                                 break;
  889.                             case checkBoxProc:
  890.                                 SetStyledCtlValue(*retCtl, GetControlValue(*retCtl) ^ 1);
  891.                                         /* Toggle checkBox value. */
  892.                                 break;
  893.                             case radioButProc:
  894.                                 nextCtl = ((WindowPeek)window)->controlList;
  895.                                     /* The below loop walks the control list for the window and
  896.                                     ** finds radio buttons of the correct family number.  If
  897.                                     ** the found radio button is the one that was clicked on,
  898.                                     ** the value is set true, otherwise it is set false. */
  899.                                 for (; nextCtl; nextCtl = (*nextCtl)->nextControl) {
  900.                                     if (GetButtonVariant(nextCtl) == radioButProc)
  901.                                         if (GetControlReference(nextCtl) == GetControlReference(*retCtl))
  902.                                             SetStyledCtlValue(nextCtl, (nextCtl == *retCtl));
  903.                                 }
  904.                                 break;
  905.                         }
  906.                         SetOrigin(org.left, org.top);
  907.                         EndContent(window);
  908.                         newVal = GetControlValue(*retCtl);
  909.                         if (oldVal != newVal) *retAction = 3;
  910.  
  911.                         if (!pass) {
  912.                             if (GetControlStyle(*retCtl, &cinfo)) {
  913.                                 for (i = 1;; i += 6) {
  914.                                     if (i >= cinfo.keyEquivs[0]) break;
  915.                                     if (cinfo.keyEquivs[i] == (unsigned char)',') ++i;
  916.                                     if (cinfo.keyEquivs[i] == (unsigned char)'\'')
  917.                                         BlockMove(cinfo.keyEquivs + i + 1, (Ptr)&sftypeNW, sizeof(OSType));
  918.                                     if (cinfo.keyEquivs[i] == (unsigned char)':') {
  919.                                         targetChr = GetHexByte((char *)(cinfo.keyEquivs + i + 1));
  920.                                         targetMod = GetHexByte((char *)(cinfo.keyEquivs + i + 2 + 1)) << 8;
  921.                                         evt.message    = targetChr;
  922.                                         evt.modifiers &= 0x00FF;
  923.                                         evt.modifiers |= (targetMod << 8);
  924.                                         if (cinfo.keyEquivs[0] > i + 4)
  925.                                             if (cinfo.keyEquivs[i + 5] == '<')
  926.                                                 --pass;
  927.                                                     /* If delimiter is a <, then reprocess with pass #0.
  928.                                                     ** This could cause an infinite loop if the targetEquiv
  929.                                                     ** is the same as what was pressed.  The reason that this
  930.                                                     ** is done is if the targetEquiv is different than the
  931.                                                     ** original event, and we want to give non-te, non-list controls
  932.                                                     ** a chance to process the equiv.  Normally the whole purpose for
  933.                                                     ** this feature is to first notice that a pass-0 control has an
  934.                                                     ** equiv, and then we want to pass this key onto a te control. */
  935.                                         i = 999;
  936.                                     }
  937.                                 }
  938.                                 if (i >= 999) continue;
  939.                             }
  940.                         }
  941.  
  942.                         if (sftypeNW) OpenActionWindow(sftypeNW);
  943.                         return(Ctl2CNum(*retCtl));
  944.                     }
  945.  
  946.                     break;
  947.                 case 1:
  948.                     if (evt.modifiers & cmdKey) break;            /* Don't allow command keys to go to te and list controls. */
  949.                     te = (*gcteFindActive)(window);
  950.                     if (te) {                                    /* If TextEdit control is active... */
  951.                         if ((*te)->viewRect.left < -8192)
  952.                             BeginFrame(window);
  953.                         else
  954.                             BeginContent(window);
  955.                         *retAction = (*gcteKey)(window, &evt);    /* Allow processing by TE control. */
  956.                         SetOrigin(org.left, org.top);
  957.                         EndContent(window);
  958.                         *retCtl = (*gcteViewFromTE)(te);
  959.                         return(Ctl2CNum(*retCtl));
  960.                     }
  961.                     list = (*gclFindActive)(window);
  962.                     if (list) {                                    /* If List control is active... */
  963.                         if ((*list)->rView.left < -8192)
  964.                             BeginFrame(window);
  965.                         else
  966.                             BeginContent(window);
  967.                         didKey = (*gclKey)(window, &evt);
  968.                         SetOrigin(org.left, org.top);
  969.                         EndContent(window);
  970.                         *retCtl = (*gclViewFromList)(list);
  971.                         ctlNum = Ctl2CNum(*retCtl);
  972.                         if (!didKey) ctlNum = 0;
  973.                         return(ctlNum);
  974.                     }
  975.                     break;
  976.             }
  977.         }
  978.     }
  979.  
  980.     return(0);
  981. }
  982.  
  983.  
  984.  
  985. /*****************************************************************************/
  986.  
  987.  
  988.  
  989. #pragma segment Controls
  990. static void    OpenActionWindow(OSType sftype)
  991. {
  992.     WindowPtr    window, fwindow;
  993.     FileRecHndl    frHndl;
  994.     long        attr, wkind;
  995.     OSErr        err;
  996.     
  997.     window = GetNextWindow(nil, sftype);
  998.     if (window) {
  999.         frHndl = (FileRecHndl)GetWRefCon(window);
  1000.         attr   = (*frHndl)->fileState.attributes;
  1001.         if (attr & kwHideOnClose) {
  1002.             if (!((WindowPeek)window)->visible)
  1003.                 ShowHide(window, true);
  1004.             wkind = (attr & (kwIsPalette | kwIsModalDialog));
  1005.             if (!(fwindow = FrontWindowOfType(wkind, false)))
  1006.                 fwindow = (WindowPtr)-1;
  1007.             CleanSendInFront(window, fwindow);
  1008.         }
  1009.         else window = nil;
  1010.     }
  1011.     if (!window) {
  1012.         err = NewDocumentWindow(&frHndl, sftype, true);
  1013.         if (!err) {
  1014.             if (frHndl) {
  1015.                 window = (*frHndl)->fileState.window;
  1016.                 attr   = (*frHndl)->fileState.attributes;
  1017.                 if (!((WindowPeek)window)->visible)
  1018.                     ShowHide(window, true);
  1019.                 wkind = (attr & (kwIsPalette | kwIsModalDialog));
  1020.                 if (!(fwindow = FrontWindowOfType(wkind, false)))
  1021.                     fwindow = (WindowPtr)-1;
  1022.                 CleanSendInFront(window, fwindow);
  1023.             }
  1024.         }
  1025.         else {
  1026.             gDialogErr = err;
  1027.             NewDocumentWindow(nil, 'ERR#', false);
  1028.         }
  1029.     }
  1030. }
  1031.  
  1032.  
  1033.  
  1034. /*****************************************************************************/
  1035.  
  1036.  
  1037.  
  1038. #pragma segment Controls
  1039. static short    HandleScrollEvent(WindowPtr window, EventRecord *event)
  1040. {
  1041.     WindowPtr        oldPort;
  1042.     Point            clickLoc;
  1043.     short            part;
  1044.     ControlHandle    ctl;
  1045.     short            value, h, v;
  1046.  
  1047.     static ControlActionUPP    cupp;
  1048.  
  1049.     GetPort(&oldPort);
  1050.     SetPort(window);
  1051.     gScrollRct = window->portRect;
  1052.  
  1053.     gKeepOrg.h = gScrollRct.left;
  1054.     gKeepOrg.v = gScrollRct.top;
  1055.  
  1056.     SetOrigin(0, -16384);
  1057.     clickLoc = event->where;
  1058.     GlobalToLocal(&clickLoc);
  1059.         /* Scrollbars for window are offset -16384 vertically.  Get a local
  1060.         ** coordinate that corresponds to this negative space. */
  1061.  
  1062.     if (!(part = FindControl(clickLoc, window, &ctl))) {
  1063.         SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  1064.         SetPort(oldPort);
  1065.         return(kScrollEvent);
  1066.     }
  1067.  
  1068.     gFrHndl = (FileRecHndl)GetWRefCon(window);
  1069.     if ((*gFrHndl)->fileState.vScroll)
  1070.         gScrollRct.right  -= 15;
  1071.     if ((*gFrHndl)->fileState.hScroll)
  1072.         gScrollRct.bottom -= 15;
  1073.  
  1074.     gScrollRct.left += (*gFrHndl)->fileState.leftSidebar;
  1075.     gScrollRct.top  += (*gFrHndl)->fileState.topSidebar;
  1076.  
  1077.     gVert = (((*ctl)->contrlRect.right - (*ctl)->contrlRect.left) == 16);
  1078.     switch (part) {
  1079.         case inThumb:
  1080.             value = GetControlValue(ctl);
  1081.             SetOrigin(0, -16384);
  1082.             part = TrackControl(ctl, clickLoc, nil);
  1083.             SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  1084.             if (part) {
  1085.                 value -= GetControlValue(ctl);
  1086.                     /* Value now has CHANGE in position.  if position changed, scroll. */
  1087.                 if (value) {
  1088.                     h = v = 0;
  1089.                     if (gVert)
  1090.                         v = value;
  1091.                     else
  1092.                         h = value;
  1093.                     ScrollTheContent(window, h, v);
  1094.                 }
  1095.             }
  1096.             break;
  1097.         default:
  1098.             SetOrigin(0, -16384);
  1099.             if (!cupp) cupp = NewControlActionProc(ScrollActionProc);
  1100.             TrackControl(ctl, clickLoc, cupp);
  1101.             SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  1102.             break;
  1103.     }
  1104.  
  1105.     AdjustScrollBars(window);
  1106.  
  1107.     SetPort(oldPort);
  1108.     return(kScrollEvent);
  1109. }
  1110.  
  1111.  
  1112.  
  1113. /*****************************************************************************/
  1114. /*****************************************************************************/
  1115.  
  1116.  
  1117.  
  1118. #pragma segment Controls
  1119. static pascal void    ScrollActionProc(ControlHandle scrollCtl, short part)
  1120. {
  1121.     WindowPtr    window;
  1122.     short        delta, value, h, v;
  1123.     short        oldValue, max;
  1124.     Point        org;
  1125.     RgnHandle    contPart, framePart;
  1126.  
  1127.     GetPort(&window);
  1128.  
  1129.     if (part) {                        /* If it was actually in the control. */
  1130.  
  1131.         switch (part) {
  1132.             case inUpButton:
  1133.             case inDownButton:        /* One line. */
  1134.                 delta = (gVert) ? (*gFrHndl)->fileState.vArrowVal : (*gFrHndl)->fileState.hArrowVal;
  1135.                 break;
  1136.             case inPageUp:            /* One page. */
  1137.             case inPageDown:
  1138.                 delta = (gVert) ? (*gFrHndl)->fileState.vPageVal : (*gFrHndl)->fileState.hPageVal;
  1139.                 break;
  1140.         }
  1141.  
  1142.         if ( (part == inUpButton) || (part == inPageUp) )
  1143.             delta = -delta;        /* Reverse direction for an upper. */
  1144.  
  1145.         value = (oldValue = GetControlValue(scrollCtl)) + delta;
  1146.         if (value < 0)
  1147.             value = 0;
  1148.         if (value > (max = GetControlMaximum(scrollCtl)))
  1149.             value = max;
  1150.  
  1151.         if (value != oldValue) {
  1152.  
  1153.             SetControlValue(scrollCtl, value);
  1154.             SetOrigin(gKeepOrg.h, gKeepOrg.v);
  1155.             h = oldValue - value;
  1156.             v = 0;
  1157.             if (gVert) {
  1158.                 v = h;
  1159.                 h = 0;
  1160.             }
  1161.  
  1162.             ScrollTheContent(window, h, v);
  1163.  
  1164.             DoUpdateSeparate(window, &contPart, &framePart);
  1165.             if (contPart) {
  1166.                 CopyRgn(contPart, ((WindowPeek)window)->updateRgn);
  1167.                 DisposeRgn(contPart);
  1168.                 ++gBeginUpdateNested;
  1169.                 BeginUpdate(window);
  1170.                 GetContentOrigin(window, &org);
  1171.                 SetOrigin(org.h, org.v);
  1172.                 DoImageDocument(gFrHndl);
  1173.                 EndUpdate(window);
  1174.                 --gBeginUpdateNested;
  1175.             }
  1176.             if (framePart) {
  1177.                 CopyRgn(framePart, ((WindowPeek)window)->updateRgn);
  1178.                 DisposeRgn(framePart);
  1179.             }
  1180.  
  1181.             SetOrigin(0, -16384);
  1182.         }
  1183.     }
  1184. }
  1185.  
  1186.  
  1187.  
  1188. /*****************************************************************************/
  1189.  
  1190.  
  1191.  
  1192. #pragma segment Controls
  1193. static void    ScrollTheContent(WindowPtr window, short h, short v)
  1194. {
  1195.     Point        org;
  1196.     RgnHandle    updateRgn;
  1197.  
  1198.     org.h = window->portRect.left;
  1199.     org.v = window->portRect.top;
  1200.     BeginContent(window);
  1201.     SetOrigin(org.h, org.v);
  1202.     ScrollRect(&gScrollRct, h, v, updateRgn = NewRgn());
  1203.     EndContent(window);
  1204.     InvalRgn(updateRgn);
  1205.     DisposeRgn(updateRgn);
  1206.     DoScrollFrame(window, h, v);
  1207. }
  1208.  
  1209.  
  1210.  
  1211. /*****************************************************************************/
  1212.  
  1213.  
  1214.  
  1215. #pragma segment Controls
  1216. static short    GetCtlPosition(ControlHandle ctl)
  1217. {
  1218.     ControlHandle    nextCtl;
  1219.     short            ctlNum;
  1220.  
  1221.     if (!ctl) return(0);
  1222.  
  1223.     nextCtl = ((WindowPeek)(*ctl)->contrlOwner)->controlList;
  1224.     for (ctlNum = 0;;) {
  1225.         if (!nextCtl) break;
  1226.         ++ctlNum;
  1227.         if (ctl == nextCtl) break;
  1228.         nextCtl = (*nextCtl)->nextControl;
  1229.     }
  1230.     return(ctlNum);
  1231. }
  1232.  
  1233.  
  1234.  
  1235. /*****************************************************************************/
  1236.  
  1237.  
  1238.  
  1239. /* Get the next Data control in the control list for a window. */
  1240.  
  1241. #pragma segment Controls
  1242. ControlHandle    CDataNext(WindowPtr window, ControlHandle ctl)
  1243. {
  1244.     ControlHandle    tempCtl;
  1245.     Rect            rct;
  1246.     static Handle    defProc;
  1247.  
  1248.     if (!window) return(nil);
  1249.  
  1250.     if (!defProc) {
  1251.         SetRect(&rct, 0, 0, 0, 0);
  1252.         tempCtl = NewControl(window, &rct, "\p", false, 0, 0, 0, gDataCtl, 0);
  1253.         if (tempCtl) {
  1254.             defProc = (*tempCtl)->contrlDefProc;
  1255.             DisposeControl(tempCtl);
  1256.         }
  1257.     }
  1258.  
  1259.     if (!ctl)
  1260.         ctl = ((WindowPeek)window)->controlList;
  1261.     else
  1262.         ctl = (*ctl)->nextControl;
  1263.  
  1264.     while (ctl) {
  1265.         LoadResource(defProc);
  1266.         if (*(*ctl)->contrlDefProc == *defProc) return(ctl);
  1267.             /* The handle may be locked, which means that the hi-bit
  1268.             ** may be on, thus invalidating the compare.  Dereference the
  1269.             ** handles to get rid of this possibility. */
  1270.         ctl = (*ctl)->nextControl;
  1271.     }
  1272.  
  1273.     return(ctl);
  1274. }
  1275.  
  1276.  
  1277.  
  1278.